package com.basker.pisces.redis.concurrent.lock;

import java.util.concurrent.TimeUnit;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

import com.basker.pisces.concurrent.lock.AbstractLock;
import com.basker.pisces.redis.utils.RedisUtils;

/**
 * 内部封装了Redisson的公平分布式锁
 *
 * @author hangwen
 */
class RedissonLock extends AbstractLock {

    private static String LOCK_PREFIX = "lock";

    @Autowired(required = false)
    private RedissonClient redissonClient;
    private RLock lock;

    public RedissonLock(String key) {
        super(key);
        this.createRLock();
    }

    public RedissonLock(String key, RedissonClient redissonClient) {
        super(key);
        this.redissonClient = redissonClient;
        this.createRLock();
    }

    @Override
    public boolean lock() {
        return this.lock.tryLock();
    }

    @Override
    public boolean lock(long waitTime, long leaseTime, TimeUnit unit) {
        try {
            return this.lock.tryLock(waitTime, leaseTime, unit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }
    }

    @Override
    public boolean lock(long waitTime, TimeUnit unit) {
        try {
            return this.lock.tryLock(waitTime, unit);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return false;
        }

    }

    @Override
    public boolean unlock() {
        if (!this.lock.isHeldByCurrentThread()) {
            return false;
        }

        try {
            this.lock.unlock();
            return true;
        } catch (IllegalMonitorStateException e) {
            return false;
        }
    }

    private void createRLock() {
        Assert.notNull(this.redissonClient, "property 'redissonClient' is required");
        this.lock = this.redissonClient.getFairLock(resolveKey());
    }

    private String resolveKey() {
        return RedisUtils.resolveKeyWithApplicationName(String.join(":", LOCK_PREFIX, this.getKey()));
    }

}
